package input

import (
	"fmt"
	"reflect"

	"gitee.com/knowgo/ego/core/errs"
	"gitee.com/knowgo/ego/core/function"
)

// ParseRequest 解析请求参数
// 返回指针类型的数据
func ParseRequest(service string, argument interface{}, argType *function.ArgumentTypeInfo, pool function.ArgumentPool) (reflect.Value, error) {
	return parse(service, "argument", argument, argType, pool, false, false)
}

type parseFn func(itemPath string, itemArgument interface{}, itemArgType *function.ArgumentTypeInfo) (reflect.Value, error)

func parse(service, path string, argument interface{}, argType *function.ArgumentTypeInfo, pool function.ArgumentPool, ignoreArrayProp, ignoreMapProp bool) (reflect.Value, error) {
	if argType.Required && argument == nil {
		return reflect.Zero(argType.TypeInfo.Type), errs.NewErrInvalidArgument(service, "%s is required", path)
	}

	// 解析数组
	if argType.Array && !ignoreArrayProp {
		// Slice 类型
		val, err := parseArray(argType, argument, func(itemPath string, itemArgument interface{}, itemArgType *function.ArgumentTypeInfo) (reflect.Value, error) {
			return parse(service, fmt.Sprintf("%s.%s", path, itemPath), itemArgument, itemArgType, pool, true, false)
		})
		if err != nil {
			return val, errs.NewErrInvalidArgument(service, "argument as array error: %s", err.Error())
		}
		return val, nil
	}

	if argType.KeyType != "" && !ignoreMapProp {
		// Map 类型
		val, err := parseMap(argType, argument, func(itemPath string, itemArgument interface{}, itemArgType *function.ArgumentTypeInfo) (reflect.Value, error) {
			return parse(service, fmt.Sprintf("%s.%s", path, itemPath), itemArgument, itemArgType, pool, false, true)
		})
		if err != nil {
			return val, errs.NewErrInvalidArgument(service, "argument as map error: %s", err.Error())
		}
		return val, nil
	}

	if argType.TypeId != "" {
		// 结构体类型
		val, err := parseStruct(argType.TypeId, pool, argument, func(itemPath string, itemArgument interface{}, itemArgType *function.ArgumentTypeInfo) (reflect.Value, error) {
			return parse(service, fmt.Sprintf("%s.%s", path, itemPath), itemArgument, itemArgType, pool, false, false)
		})
		if err != nil {
			return val, errs.NewErrInvalidArgument(service, "argument as struct error: %s", err.Error())
		}
		return val, nil
	}

	// 解析时间
	if argType.Time {
		// 解析为时间类型
		val, err := parseTime(argType, argument)
		if err != nil {
			return val, errs.NewErrInvalidArgument(service, "%s as time error: %s", path, err.Error())
		}
		return val, nil
	}

	// 解析原生类型
	return parsePrimitive(argType, argument)

	// return reflect.ValueOf(nil), nil
}
